import {
  Body,
  Controller,
  DefaultValuePipe,
  Get,
  Inject,
  Param,
  ParseIntPipe,
  Patch,
  Post,
  Query,
  UploadedFile,
  UseInterceptors,
} from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { UserService } from './user.service';
import { RegisterUserDto } from 'src/dto/RegisterUser.dto';
import { RedisService } from 'src/redis/redis.service';
import { EmailService } from 'src/email/email.service';
import { LoginDto } from 'src/dto/Login.dto';
import { LoginVo } from 'src/vo/Login.vo';
import { JwtService } from '@nestjs/jwt';
import { ConfigService } from '@nestjs/config';
import {
  RequireLogin,
  RequirePermission,
  UserInfo,
} from 'src/decorator/index.decorator';
import { UpdateUserPasswordDto } from 'src/dto/UpdateUserPasswordDto .dto';
import { SendEmailDto } from 'src/dto/SendEmailDto.dto';
import { RedisPrefix } from 'src/enum';
import { UpdateUserDto } from 'src/dto/UpdateUserDto.dto';
import { UnloginException } from 'src/filter/unlogin.filter';
import { storage } from 'src/utils';

@Controller('user')
export class UserController {
  @Inject(UserService)
  private readonly userService: UserService;

  @Inject(RedisService)
  private readonly redisService: RedisService;

  @Inject(EmailService)
  private readonly emailService: EmailService;

  @Inject(JwtService)
  private readonly jwtService: JwtService;

  @Inject(ConfigService)
  private readonly configService: ConfigService;

  @Post('login')
  async login(@Body() loginUser: LoginDto) {
    const vo: LoginVo = await this.userService.login(loginUser);

    vo.accessToken = this.jwtService.sign(
      {
        userId: vo.userInfo.id,
        username: vo.userInfo.username,
        roles: vo.userInfo.roles,
        permissions: vo.userInfo.permissions,
      },
      {
        expiresIn: this.configService.get('jwt.access_token_expires') || '30m',
      },
    );

    vo.refreshToken = this.jwtService.sign(
      {
        userId: vo.userInfo.id,
      },
      {
        expiresIn: this.configService.get('jwt.refresh_token_expires') || '7d',
      },
    );

    return vo;
  }

  @Post('refresh')
  async refreshToken(@Body('refreshToken') refreshToken: string) {
    try {
      const data = await this.jwtService.verifyAsync(refreshToken);
      const user = await this.userService.findUserById(data.userId);

      const access_token = this.jwtService.sign(
        {
          userId: user.id,
          username: user.username,
          roles: user.roles,
          permissions: user.permissions,
        },
        {
          expiresIn:
            this.configService.get('jwt.access_token_expires') || '30m',
        },
      );
      return { access_token };
    } catch (e) {
      throw new UnloginException('token 已失效，请重新登录');
    }
  }

  @Post('register')
  register(@Body() registerUser: RegisterUserDto) {
    return this.userService.register(registerUser);
  }

  @Post('sendEmail')
  async sendEmail(@Body() sendEmailDto: SendEmailDto) {
    const code = Math.random().toString().slice(2, 8);

    // type 0:注册、1：修改密码、2：修改用户信息
    const prefix = [
      RedisPrefix.REGISTER,
      RedisPrefix.UPDATE_PASSWORD,
      RedisPrefix.UPDATE_USER,
    ];

    await this.redisService.set(
      `${prefix[sendEmailDto.type]}_${sendEmailDto.address}`,
      code,
      60 * 5,
    );
    await this.emailService.sendMail({
      to: sendEmailDto.address,
      subject: '验证码',
      html: `<p>您的验证码是: ${code}, 5分钟内有效, 请妥善保管</p>`,
    });
    return `发送成功, ${code}`;
  }

  @Get('info')
  @RequireLogin()
  async getUserInfo(@UserInfo('userId') userId: number) {
    const user = await this.userService.findUserById(userId);
    // eslint-disable-next-line
    const { roles, permissions, ...vo } = user;
    return vo;
  }

  @Patch('updatePassword')
  @RequireLogin()
  async updatePasssword(
    @UserInfo('userId') userId: number,
    @Body() passwordDto: UpdateUserPasswordDto,
  ) {
    return await this.userService.updatePassword(userId, passwordDto);
  }

  @Patch('updateInfo')
  @RequireLogin()
  async updateInfo(
    @UserInfo('userId') userId: number,
    @Body() updateUserDto: UpdateUserDto,
  ) {
    return await this.userService.updateInfo(userId, updateUserDto);
  }

  @Post('upload')
  @RequireLogin()
  @UseInterceptors(
    FileInterceptor('file', {
      dest: 'uploads',
      storage,
      limits: {
        fileSize: 1024 * 1024 * 3,
      },
      fileFilter: (req, file, cb) => {
        if (file.mimetype.match(/\/(jpg|jpeg|png)$/)) {
          cb(null, true);
        } else {
          cb(new Error('只能上传图片'), false);
        }
      },
    }),
  )
  async uploadAvatar(@UploadedFile() file: Express.Multer.File) {
    return file.path;
  }

  @Get('list')
  @RequireLogin()
  @RequirePermission('show_userList')
  async getUserList(
    @Query('pageNum', new DefaultValuePipe(1), ParseIntPipe) pageNum: number,
    @Query('pageSize', new DefaultValuePipe(999999), ParseIntPipe)
    pageSize: number,
    @Query('username') username: string,
    @Query('nickname') nickname: string,
    @Query('email') email: string,
  ) {
    return await this.userService.getUserList(
      pageNum,
      pageSize,
      username,
      nickname,
      email,
    );
  }

  @Get('freeze/:id')
  @RequireLogin()
  @RequirePermission('freeze_user')
  async freezeUser(@Param('id', ParseIntPipe) id: number) {
    return await this.userService.freezeUser(id);
  }
}
